/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mobsandgeeks.adapters.samples;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.multimodalinput.event.TouchEvent;

/**
 * 水波纹
 *
 * @since 2021-07-08
 */
public class RippleView extends DependentLayout implements Component.DrawTask,
        Component.TouchEventListener, Component.LongClickedListener {
    private static final int NUM10 = 10;
    private static final float NUM09 = 0.9F;
    private static final float NUM04 = 0.4F;
    private static final float NUM06 = 0.6F;
    private static final float NUM1D03 = 1.03F;
    private static final float NUM50F = 50F;
    private static final float NUM2F = 2F;
    private static final float NUM03F = 0.3F;
    private static final int NUM2 = 2;
    private static final int NUM160 = 160;
    private static final int NUM1 = 1;
    private static final int NUM3 = 3;
    private static final int NUM50 = 50;
    private static final int NUM800 = 300;
    private static final int WHITE = 0xFFFFFFF;
    private static final int GRAY = 0xEEBEBEBE;
    private static final int NUM250 = 250;
    private static final int NUM5 = 5;
    private static final int NUM200 = 200;
    private int frameRate;
    private int rippleDuration;
    private float rippleAlpha;
    private float radiusMax;
    private boolean isAnimationRunning;
    private int zoomDuration;
    private float zoomScale;
    private AnimatorValue rippleAnimation;
    private float ripplePose;
    private boolean isHasToZoom;
    private boolean isCentered;
    private int rippleType;
    private Paint paint;
    private Paint pain2;
    private int rippleColor;
    private int ripplePadding;
    private float touchX;
    private float touchY;
    private boolean isDownPose;
    private boolean isSlide;
    private float downX;
    private float downY;
    private long downTime;
    private boolean isYinYing = false;
    private RippleView.OnRippleCompleteListener onCompletionListener;
    private EventHandler myevenHandler = new EventHandler(EventRunner.getMainEventRunner()) {
        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event.eventId == 1) {
                RippleView.this.invalidate();
            }
        }
    };

    /**
     * 构造
     *
     * @param var1 Context
     */
    public RippleView(Context var1) {
        super(var1);
    }

    /**
     * 构造
     *
     * @param var1 Context
     * @param var2 AttrSet
     */
    public RippleView(Context var1, AttrSet var2) {
        this(var1, var2, (String) null);
    }

    /**
     * 构造
     *
     * @param var1 Context
     * @param var2 AttrSet
     * @param var3 String
     */
    public RippleView(Context var1, AttrSet var2, String var3) {
        super(var1, var2, var3);
        this.frameRate = NUM10;
        this.rippleDuration = NUM800;
        this.rippleAlpha = NUM09;
        this.radiusMax = 0.0F;
        this.isAnimationRunning = false;
        this.zoomScale = NUM1D03;
        this.rippleType = 0;
        this.rippleColor = Color.GRAY.getValue();
        this.isDownPose = false;
        this.isSlide = false;
        this.init(var2);
    }

    /**
     * 初始化
     *
     * @param var1 AttrSet
     */
    private void init(AttrSet var1) {
        this.rippleColor = AttrUtils.getColorFromAttr(var1, "rv_color", this.rippleColor);
        this.rippleType = AttrUtils.getIntFromAttr(var1, "rv_type", 0);
        this.isHasToZoom = AttrUtils.getBooleanFromAttr(var1, "rv_zoom", false);
        this.isCentered = AttrUtils.getBooleanFromAttr(var1, "rv_centered", false);
        this.rippleDuration = AttrUtils.getIntFromAttr(var1, "rv_rippleDuration", this.rippleDuration);
        this.rippleAlpha = AttrUtils.getFloatFromAttr(var1, "rv_alpha", this.rippleAlpha);
        this.ripplePadding = AttrUtils.getDimensionFromAttr(var1, "rv_ripplePadding", 0);
        this.zoomScale = AttrUtils.getFloatFromAttr(var1, "rv_zoomScale", NUM1D03);
        this.zoomDuration = AttrUtils.getIntFromAttr(var1, "rv_zoomDuration", NUM50);

        this.pain2 = new Paint();
        this.pain2.setAntiAlias(true);
        this.pain2.setColor(new Color(Color.getIntColor("#C0C0C0")));

        this.paint = new Paint();
        this.paint.setAntiAlias(true);
        this.paint.setColor(new Color(this.rippleColor));
        this.radiusMax = (float) Math.sqrt(this.getWidth() * this.getWidth() + this.getHeight() * this.getHeight());
        this.setTouchEventListener(this);
        this.setLongClickedListener(this);
        this.addDrawTask(this);
    }

    @Override
    public void onLongClicked(Component component) {
        this.createAnimation(this.downX, this.downY);
        myevenHandler.sendEvent(1, NUM250);
        this.isSlide = true;
    }

    /**
     * onTouchEvent
     *
     * @param component component
     * @param touchEvent touchEvent
     * @return 是否消费
     */
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (touchEvent.getPointerCount() == NUM1 && touchEvent.getAction() == NUM1) {
            this.downX = this.getTouchX(touchEvent, 0);
            this.downY = this.getTouchY(touchEvent, 0);
            this.downTime = System.currentTimeMillis();
            this.isDownPose = true;
            this.isSlide = false;
            isYinYing = false;
        } else if (touchEvent.getPointerCount() == NUM1 && touchEvent.getAction() == NUM3) {
            float upx = this.getTouchX(touchEvent, 0);
            long theTime = System.currentTimeMillis();
            int xjuli = (int) Math.abs(upx - downX);
            int timejuli = (int) Math.abs(theTime - this.downTime);
            if (isDownPose && timejuli > NUM200 && xjuli < NUM2 && !isSlide) {
                this.createAnimation(this.getTouchX(touchEvent, 0), this.getTouchY(touchEvent, 0));
                myevenHandler.sendEvent(1, NUM250);
                this.isSlide = true;
                return true;
            }
            return true;
        } else if (touchEvent.getPointerCount() == NUM1 && touchEvent.getAction() == NUM2) {
            float upx = this.getTouchX(touchEvent, 0);
            long upTimes = System.currentTimeMillis();
            isDownPose = false;
            isYinYing = false;
            int xjuli = (int) Math.abs(upx - downX);
            if (!this.isDownPose && upTimes - this.downTime < NUM200 && xjuli < NUM5) {
                this.isDownPose = false;
                this.createAnimation(this.getTouchX(touchEvent, 0), this.getTouchY(touchEvent, 0));
            } else if (!this.isDownPose && System.currentTimeMillis() - this.downTime > NUM250) {
                this.invalidate();
            } else {
                this.isDownPose = false;
            }
            this.isDownPose = false;
        }
        return true;
    }

    /**
     * 绘制
     *
     * @param var1 Component
     * @param var2 Canvas
     */
    public void onDraw(Component var1, Canvas var2) {
        if (isYinYing) {
            this.paint.setAlpha(NUM03F);
            var2.drawCircle(this.touchX, this.touchY, this.radiusMax * this.ripplePose - 0 / NUM2F, this.paint);
        } else {
            if (this.getWidth() != 0 && this.getHeight() != 0) {
                this.radiusMax = (float) Math.sqrt(this.getWidth()
                        * this.getWidth() + this.getHeight() * this.getHeight());
                if (this.rippleType != NUM2) {
                    this.radiusMax /= NUM2F;
                }
                this.radiusMax -= (float) this.ripplePadding;
                if (this.isCentered || this.rippleType == 1) {
                    this.touchX = (float) this.getWidth() / NUM2F;
                    this.touchY = (float) this.getHeight() / NUM2F;
                }
                this.paint.setAlpha(this.rippleAlpha - this.rippleAlpha * this.ripplePose);
                float var3 = 0.0F;
                if (this.rippleType == NUM1 && this.ripplePose > NUM04) {
                    this.paint.setStyle(Paint.Style.STROKE_STYLE);
                    var3 = this.radiusMax * this.ripplePose - this.radiusMax * (this.ripplePose - NUM04) / NUM06;
                    this.paint.setStrokeWidth(this.radiusMax * this.ripplePose
                            - this.radiusMax * (this.ripplePose - NUM04) / NUM06);
                } else {
                    this.paint.setStyle(Paint.Style.FILL_STYLE);
                }
                var2.drawCircle(this.touchX, this.touchY, this.radiusMax * this.ripplePose - var3 / NUM2F, this.paint);
            }
        }
    }

    /**
     * scaleAnimation
     */
    private void scaleAnimation() {
        AnimatorGroup animatorGroup = new AnimatorGroup();
        AnimatorProperty var2 = new AnimatorProperty(this).setDuration(this.zoomDuration);
        var2.scaleX(this.zoomScale).scaleY(this.zoomScale);
        AnimatorProperty var3 = new AnimatorProperty(this).setDuration(this.zoomDuration);
        var3.scaleX(1.0F).scaleY(1.0F);
        animatorGroup.build().addAnimators(new Animator[]{var2}).addAnimators(new Animator[]{var3});
        animatorGroup.start();
    }

    /**
     * createAnimation
     *
     * @param var1 float
     * @param var2 float
     */
    private void createAnimation(float var1, float var2) {
        if (this.isEnabled() && !this.isAnimationRunning) {
            if (this.isHasToZoom) {
                this.scaleAnimation();
            }

            if (this.rippleAnimation == null) {
                this.rippleAnimation = new AnimatorValue();
                this.rippleAnimation.setDuration((long) this.rippleDuration);
                this.rippleAnimation.setValueUpdateListener((var1x, var2x) -> {
                    this.ripplePose = var2x;
                    this.invalidate();
                });
                this.rippleAnimation.setStateChangedListener(new Animator.StateChangedListener() {
                    public void onStart(Animator var1) {
                    }

                    public void onStop(Animator var1) {
                        if (isDownPose) {
                            isYinYing = true;
                            RippleView.this.invalidate();
                        }
                    }

                    public void onCancel(Animator var1) {
                    }

                    public void onEnd(Animator var1) {
                        RippleView.this.isAnimationRunning = false;
                    }

                    public void onPause(Animator var1) {
                    }

                    public void onResume(Animator var1) {
                    }
                });
            }

            if (this.rippleAnimation.isRunning()) {
                return;
            }

            this.isAnimationRunning = true;
            this.touchX = var1;
            this.touchY = var2;
            this.rippleAnimation.start();
        }
    }

    /**
     * TouchEvent
     *
     * @param var1 TouchEvent
     * @param var2 int
     * @return float
     */
    private float getTouchX(TouchEvent var1, int var2) {
        float var3 = 0.0F;
        if (var1.getPointerCount() > var2) {
            int[] var4 = this.getLocationOnScreen();
            if (var4 != null && var4.length == NUM2) {
                var3 = var1.getPointerScreenPosition(var2).getX() - (float) var4[0];
            } else {
                var3 = var1.getPointerPosition(var2).getX();
            }
        }

        return var3;
    }

    private float getTouchY(TouchEvent var1, int var2) {
        float var3 = 0.0F;
        if (var1.getPointerCount() > var2) {
            int[] var4 = this.getLocationOnScreen();
            if (var4 != null && var4.length == NUM2) {
                var3 = var1.getPointerScreenPosition(var2).getY() - (float) var4[1];
            } else {
                var3 = var1.getPointerPosition(var2).getY();
            }
        }

        return var3;
    }

    /**
     * animateRipple
     *
     * @param var1 TouchEvent
     */
    public void animateRipple(TouchEvent var1) {
        this.createAnimation(this.getTouchX(var1, 0), this.getTouchY(var1, 0));
    }

    /**
     * animateRipple
     *
     * @param var1 动画起始点
     * @param var2 结束点
     */
    public void animateRipple(float var1, float var2) {
        this.createAnimation(var1, var2);
    }

    public void setRippleColor(int var1) {
        this.rippleColor = var1;
    }

    public int getRippleColor() {
        return this.rippleColor;
    }

    public RippleView.RippleType getRippleType() {
        return RippleView.RippleType.values()[this.rippleType];
    }

    public void setRippleType(RippleView.RippleType var1) {
        this.rippleType = var1.ordinal();
    }

    public boolean isCentered() {
        return this.isCentered;
    }

    public void setCentered(Boolean isVar1) {
        this.isCentered = isVar1;
    }

    public int getRipplePadding() {
        return this.ripplePadding;
    }

    public void setRipplePadding(int isVar1) {
        this.ripplePadding = isVar1;
    }

    public boolean isZooming() {
        return this.isHasToZoom;
    }

    public void setZooming(Boolean isVar1) {
        this.isHasToZoom = isVar1;
    }

    public float getZoomScale() {
        return this.zoomScale;
    }

    public void setZoomScale(float var1) {
        this.zoomScale = var1;
    }

    public int getZoomDuration() {
        return this.zoomDuration;
    }

    public void setZoomDuration(int var1) {
        this.zoomDuration = var1;
    }

    public int getRippleDuration() {
        return this.rippleDuration;
    }

    public void setRippleDuration(int var1) {
        this.rippleDuration = var1;
    }

    public int getFrameRate() {
        return this.frameRate;
    }

    public void setFrameRate(int var1) {
        this.frameRate = var1;
    }

    public float getRippleAlpha() {
        return this.rippleAlpha;
    }

    public void setRippleAlpha(float var1) {
        this.rippleAlpha = var1;
    }

    public void setOnRippleCompleteListener(RippleView.OnRippleCompleteListener var1) {
        this.onCompletionListener = var1;
    }

    public OnRippleCompleteListener getOnCompletionListener() {
        return onCompletionListener;
    }

    private int dp2px(float var1) {
        int screenDensity = this.getResourceManager().getDeviceCapability().screenDensity;
        int density = screenDensity / NUM160;
        return (int)(density * var1);
    }

    /**
     * RippleType
     *
     * @since 2021-04-06
     */
    public enum RippleType {
        /**
         * SIMPLE
         */
        SIMPLE(0),
        /**
         * DOUBLE
         */
        DOUBLE(NUM1),
        /**
         * RECTANGLE
         */
        RECTANGLE(NUM2);

        int type;

        RippleType(int var3) {
            this.type = var3;
        }
    }

    /**
     * OnRippleCompleteListener
     *
     * @since 2021-04-06
     */
    public interface OnRippleCompleteListener {
        /**
         * onComplete
         *
         * @param var1 RippleView
         */
        void onComplete(RippleView var1);
    }
}